#ifndef __UIMARKUP_H__
#define __UIMARKUP_H__

#pragma once

namespace DuiLib {

    enum
    {
        XMLFILE_ENCODING_UTF8 = 0,
        XMLFILE_ENCODING_UNICODE = 1,
        XMLFILE_ENCODING_ASNI = 2,
    };

    class CMarkup;
    class CMarkupNode;


    class UILIB_API CMarkup
    {
        friend class CMarkupNode;
    public:
        CMarkup(LPCTSTR pstrXML = NULL);
        ~CMarkup();

        bool Load(LPCTSTR pstrXML);
        bool LoadFromMem(BYTE* pByte, DWORD dwSize, int encoding = XMLFILE_ENCODING_UTF8);
        bool LoadFromFile(LPCTSTR pstrFilename, int encoding = XMLFILE_ENCODING_UTF8);
        void Release();
        bool IsValid() const;

        void SetPreserveWhitespace(bool bPreserve = true);
        void GetLastErrorMessage(LPTSTR pstrMessage, SIZE_T cchMax) const;
        void GetLastErrorLocation(LPTSTR pstrSource, SIZE_T cchMax) const;

        CMarkupNode GetRoot();

    private:
        typedef struct tagXMLELEMENT
        {
            ULONG iStart;
            ULONG iChild;
            ULONG iNext;
            ULONG iParent;
            ULONG iData;
        } XMLELEMENT;

        LPTSTR m_pstrXML;
        XMLELEMENT* m_pElements;
        ULONG m_nElements;
        ULONG m_nReservedElements;
        TCHAR m_szErrorMsg[100];
        TCHAR m_szErrorXML[50];
        bool m_bPreserveWhitespace;

    private:
        bool _Parse();
        bool _Parse(LPTSTR& pstrText, ULONG iParent);
        XMLELEMENT* _ReserveElement();
        inline void _SkipWhitespace(LPTSTR& pstr) const;
        inline void _SkipWhitespace(LPCTSTR& pstr) const;
        inline void _SkipIdentifier(LPTSTR& pstr) const;
        inline void _SkipIdentifier(LPCTSTR& pstr) const;
        bool _ParseData(LPTSTR& pstrText, LPTSTR& pstrData, char cEnd);
        void _ParseMetaChar(LPTSTR& pstrText, LPTSTR& pstrDest);
        bool _ParseAttributes(LPTSTR& pstrText);
        bool _Failed(LPCTSTR pstrError, LPCTSTR pstrLocation = NULL);
    };


    class UILIB_API CMarkupNode
    {
        friend class CMarkup;
    private:
        CMarkupNode();
        CMarkupNode(CMarkup* pOwner, int iPos);

    public:
        bool IsValid() const;

        CMarkupNode GetParent();
        CMarkupNode GetSibling();
        CMarkupNode GetChild();
        CMarkupNode GetChild(LPCTSTR pstrName);

        bool HasSiblings() const;
        bool HasChildren() const;
        LPCTSTR GetName() const;
        LPCTSTR GetValue() const;

        bool HasAttributes();
        bool HasAttribute(LPCTSTR pstrName);
        int GetAttributeCount();
        LPCTSTR GetAttributeName(int iIndex);
        LPCTSTR GetAttributeValue(int iIndex);
        LPCTSTR GetAttributeValue(LPCTSTR pstrName);
        bool GetAttributeValue(int iIndex, LPTSTR pstrValue, SIZE_T cchMax);
        bool GetAttributeValue(LPCTSTR pstrName, LPTSTR pstrValue, SIZE_T cchMax);

    private:
        void _MapAttributes();

        enum { MAX_XML_ATTRIBUTES = 64 };

        typedef struct
        {
            ULONG iName;
            ULONG iValue;
        } XMLATTRIBUTE;

        int m_iPos;
        int m_nAttributes;
        XMLATTRIBUTE m_aAttributes[MAX_XML_ATTRIBUTES];
        CMarkup* m_pOwner;
    };

} // namespace DuiLib

#endif // __UIMARKUP_H__
